/*********************************************************
/*     Copyright (c) 2020 上海芯翌智能科技有限公司     
/*       公司内部代码, 未经允许, 不得使用和传播.       
**********************************************************/

#ifndef _XFFWCC_LOG_LOGGER_H_
#define _XFFWCC_LOG_LOGGER_H_

#include <assert.h>
#include <iomanip>
#include <iostream>
#include <string>
#include <thread>
#include <cstdint>

//#include "logtm.h"
#include "log_stream.h"
#include "spdlog/spdlog.h"

namespace xffwcc {
namespace log {

//1mb size
const uint64_t kSizeM = 1024 * 1024;
//1gb size
const uint64_t kSizeG = kSizeM * 1024;
const uint64_t kDefaultSize = 500;
const size_t kDefaultMaxFiles = 10;


using LogLevel = spdlog::level::level_enum;

class Logger {
 public:
  Logger(const char *file, int line, spdlog::level::level_enum level)
      : cpp_file_(file), level_(level), line_(line) {
#ifdef WIN32
    auto post = cpp_file_.rfind('/\\', cpp_file_.length() - 1);
#else
	auto post = cpp_file_.rfind('/', cpp_file_.length() - 1);
#endif
    cpp_file_= cpp_file_.substr(post + 1, cpp_file_.length());
  }

  ~Logger() { writeLog(); }

  // Description:Get a log stream obj for log stream input.
  // Auth: yingchun.zhang on 2020/3/20.
  LogStream &stream() { return log_stream; }

  // Description:Get log_level.
  // Auth: yingchun.zhang on 2020/3/20.
  static LogLevel log_level() { return log_level_; }

  // Description:Set log_level.
  // Auth: yingchun.zhang on 2020/3/20.
  // Parameters:
  //	level -Log level.
  static void set_level(LogLevel level) {
    log_level_ = level;
    spdlog::set_level(log_level_);
  }

  // Description:Set the log refresh interva.
  // Auth: yingchun.zhang on 2020/3/20.
  // Parameters:
  //	interval -The unit is second.
  static void flush_every(std::chrono::seconds interval) {
    spdlog::flush_every(interval);
  }
  
  // Description:Initialized before use.
  // Auth: yingchun.zhang on 2020/3/20.
  // Parameters:
  //	filename -The name of the file on which the log is saved.
  //    is_async -Log whether to turn on asynchronous mode.
  //    max_file_size -The size of a single log file.
  //    max_files -Number of saved log files.
  //    rotate_on_open -Whether the log is scrolling or not. if true,
  //	the earliest log file is overwritten when the number of log
  //	files exceeds max_files.
  static void init_logger(std::string filename,
                          bool is_async = true,
                          uint64_t max_file_size = kDefaultSize,
                          size_t max_files = kDefaultMaxFiles,
                          bool rotate_on_open = true);

  // Description:Set the log refresh interva.
  // Auth: yingchun.zhang on 2020/3/20.
  // Parameters:
  //	pattern -The log pattern.
  // referenced document：
  //	http://wiki.xforwardai.io/pages/viewpage.action?pageId=3080244
  static void set_pattern(std::string pattern) { spdlog::set_pattern(pattern); }

  // Description: Write log without header.
  // Parameters:
  //  -msg: message to be written.
  // Returns:
  //  -none.
  static void write_raw(std::string msg) { spdlog::error(msg); }

  // Description:Destroy the log and flush the buffer, 
  //			writing all unwritten logs to the log file.
  // Auth: yingchun.zhang on 2020/3/20.
  static void destory_logger() { spdlog::shutdown(); };

 private:
  // Description:Write log
  // Auth: yingchun.zhang on 2020/3/20.
  void writeLog();

 private:
  //log stream obj.
  LogStream log_stream;
  //file name of log occurrence.
  std::string cpp_file_;
  //log level
  LogLevel level_;
  //file name of log occurrence
  int line_;
  // const char *function_;

 public:
  //log write level
  static LogLevel log_level_;
  //log whether to turn on asynchronous mode.
  static bool is_async_;
  static std::shared_ptr<spdlog::logger> logger_;
  static std::shared_ptr<spdlog::details::thread_pool> th_pool_;
  static std::string default_pattern_;
};
}  // namespace log
}  // namespace xffwcc

#ifndef LOG_TRACE
#define LOG_TRACE                                                           \
  if (xffwcc::log::Logger::log_level() <= spdlog::level::level_enum::trace) \
  xffwcc::log::Logger(__FILE__, __LINE__, spdlog::level::level_enum::trace) \
      .stream()
#endif

#ifndef LOG_DEBUG
#define LOG_DEBUG                                                           \
  if (xffwcc::log::Logger::log_level() <= spdlog::level::level_enum::debug) \
  xffwcc::log::Logger(__FILE__, __LINE__, spdlog::level::level_enum::debug) \
      .stream()
#endif

#ifndef LOG_INFO
#define LOG_INFO                                                           \
  if (xffwcc::log::Logger::log_level() <= spdlog::level::level_enum::info) \
  xffwcc::log::Logger(__FILE__, __LINE__, spdlog::level::level_enum::info) \
      .stream()
#endif

#ifndef LOG_WARN
#define LOG_WARN                                                           \
  xffwcc::log::Logger(__FILE__, __LINE__, spdlog::level::level_enum::warn) \
      .stream()
#endif

#ifndef LOG_ERROR
#define LOG_ERROR                                                         \
  xffwcc::log::Logger(__FILE__, __LINE__, spdlog::level::level_enum::err) \
      .stream()
#endif

#endif